package com.bluexmicro.android.ota

import android.bluetooth.BluetoothDevice
import android.content.Context
import android.util.Log
import com.bluexmicro.android.ota.entity.OtaTask
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.catch
import java.util.*


/**
 * 使用场景
 * 1. 进入表盘市场 -> OtaTransaction.shared().startTransaction
 *
 * 2. 下载表盘1：-> OtaTransaction.shared().execute(task1)
 *    下载表盘2：-> OtaTransaction.shared().execute(task2)
 *    下载表盘3：-> OtaTransaction.shared().execute(task3)
 *    ...
 *
 * 3. 退出表盘市场或者不再下载表盘 -> OtaTransaction.endTransaction
 */
class OtaTransaction {

    private var coroutineScope: CoroutineScope? = null
    private var core: CoroutineOta? = null
    private var updating = false

    fun startTransaction(
        context: Context,
        device: BluetoothDevice,
        fastMode: Boolean,
        callback: TransactionLaunchCallback
    ) {
        if (updating) {
            callback.onResult(
                false,
                "Maybe there is another OTA task in progress.Please call <endTransaction>."
            )
            return
        }
        coroutineScope?.takeIf { it.isActive }?.apply { cancel() }
        coroutineScope = CoroutineScope(Dispatchers.Default)
        coroutineScope!!.launch {
            try {
                val coroutineOta = CoroutineOta(context, device)
                core = coroutineOta
                coroutineOta.startTransaction(fastMode)
                callback.onResult(true, null)
            } catch (e: Exception) {
                callback.onResult(false, e.message ?: "Unknown Error")
                coroutineScope?.takeIf { it.isActive }?.apply { cancel() }
            }
        }
    }

    fun execute(task: OtaTask, fastMode: Boolean, callback: SingleTransactionTaskCallback) {
        if (coroutineScope == null || coroutineScope?.isActive == false || core == null) {
            callback.onResult(false, "Please call function<startTransaction> first")
            return
        }
        coroutineScope!!.launch {
            var result = true
            updating = true
            core!!.execute(task, fastMode)
                .catch {
                    updating = false
                    result = false
                    core?.reset()
                    callback.onResult(false, it.message ?: "Unknown Error")
                }.collect {
                    callback.onProgress(it)
                }
            updating = false
            if (result) callback.onResult(true, null)

        }
    }

    fun endTransaction(fastMode: Boolean) {
        updating = false
        coroutineScope?.takeIf { it.isActive }?.launch {
            core?.endTransaction(fastMode)
            delay(500)
            Log.d("TAG", "endTransaction: ")
            cancel()
            coroutineScope = null
        }
    }

    companion object {
        @Volatile
        private var core: OtaTransaction? = null

        fun shared(): OtaTransaction {
            return core ?: synchronized(this) {
                return core ?: OtaTransaction().also { core = it }
            }
        }
    }
}

interface TransactionLaunchCallback {
    fun onResult(result: Boolean, errorMessage: String?)
}

interface SingleTransactionTaskCallback {
    fun onProgress(value: Float)
    fun onResult(result: Boolean, errorMessage: String?)
}